Skip to content

security(oauth): restrict OAuth signing-key settings to system admins#265

Open
gonzalesedwin1123 wants to merge 2 commits into
19.0from
security-oauth-signing-keys-acl
Open

security(oauth): restrict OAuth signing-key settings to system admins#265
gonzalesedwin1123 wants to merge 2 commits into
19.0from
security-oauth-signing-keys-acl

Conversation

@gonzalesedwin1123

Copy link
Copy Markdown
Member

Problem

spp_oauth granted base.group_user (every internal user) read + write on
res.config.settings, which exposes oauth_priv_key — the RS256 JWT signing key used
by calculate_signature() — and oauth_pub_key. A low-privileged internal user could:

  • Read the private key and forge OAuth/JWT tokens that verify_and_decode_signature()
    accepts (full API auth bypass / impersonation), and
  • Overwrite the keypair to break or subvert authentication (tamper / DoS).

Severity: High/Critical — this is a signing credential, not a config toggle.

Why the ACL fix alone is not enough

res.config.settings.default_get() (Odoo core base/models/res_config.py) reads
config_parameter fields via ir.config_parameter.sudo() and performs no model-ACL or
field-group check. It is an @api.model method reachable over RPC, so
env['res.config.settings'].default_get(['oauth_priv_key']) leaks the key regardless of the
ACL
. This was reproduced by a failing test before the fix (the plain-user default_get
result contained the private key). Both changes below are required.

Changes

  1. Remove the over-broad ir.model.access row. Odoo core already grants
    res.config.settings to base.group_system (read/write/create), so system admins keep
    full access and can still Save settings. This was the only module in the repo widening this
    model to base.group_user.
  2. Override default_get to strip oauth_priv_key/oauth_pub_key for users who are not
    base.group_system, closing the sudo RPC path. (A groups= field attribute would not fix
    this — field groups are not enforced in default_get's config loop.)
  3. Bump manifest 19.0.2.0.019.0.2.0.1.

Tests

New spp_oauth/tests/test_config_settings_acl.py:

  • plain internal user is denied model access to res.config.settings (AccessError);
  • plain internal user cannot read the keys via default_get;
  • system admin retains model access and can read both keys via default_get.

Written test-first (failing → passing). ./spp test spp_oauth14 passed, 0 failed;
./spp lint clean.

⚠️ Operational remediation required

Every internal user has had read access to the signing key historically, so the deployed
RSA keypair must be treated as compromised. After upgrading, operators should rotate
(regenerate) the keypair and invalidate any outstanding tokens. A code fix cannot un-leak an
already-exposed key.

Out of scope (noted for awareness)

  • Placeholder values in data/ir_config_parameter_data.xml (YourPrivateKeyHere /
    YourPublicKeyHere) are non-secret placeholders.
  • Empty 0-byte spp_oauth/tools/private_key.pem / public_key.pub are unused (keys are read
    only from ir.config_parameter).
  • password="true" on the settings view fields is display masking only, not an access control.

The module granted base.group_user read/write on res.config.settings, which
exposes oauth_priv_key (the RS256 JWT signing key) and oauth_pub_key. Any
internal user could read the private key via RPC and forge OAuth/JWT tokens, or
overwrite the keypair to break/subvert authentication.

- Remove the over-broad ir.model.access row. Odoo core already grants
  res.config.settings to base.group_system (read/write/create), so admins keep
  full access and can still save settings.
- Override default_get to strip the signing-key fields for non-system-admins.
  default_get reads config_parameter values via sudo() with no model/field
  access check, so the ACL change alone would not stop key exfiltration over RPC.
- Add regression tests asserting a plain internal user is denied model access
  and cannot read the keys via default_get, while a system admin retains both.

Operators should treat the deployed keypair as compromised and rotate it.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances security by restricting access to OAuth signing keys to system administrators. It removes broad read/write access to res.config.settings for standard users and overrides default_get to filter out sensitive keys for non-admins, backed by new integration tests. The feedback suggests ensuring that custom group checks bypass restrictions when running in superuser mode (self.env.su) to prevent unexpected behavior during elevated executions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread spp_oauth/models/res_config_settings.py Outdated
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.30%. Comparing base (02de7ba) to head (ba0b5f2).
⚠️ Report is 17 commits behind head on 19.0.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             19.0     #265   +/-   ##
=======================================
  Coverage   75.30%   75.30%           
=======================================
  Files        1095     1095           
  Lines       64991    64998    +7     
=======================================
+ Hits        48939    48946    +7     
  Misses      16052    16052           
Flag Coverage Δ
spp_base_common 90.26% <ø> (ø)
spp_oauth 97.82% <100.00%> (+0.39%) ⬆️
spp_programs 65.27% <ø> (ø)
spp_registry 86.83% <ø> (ø)
spp_security 66.66% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
spp_oauth/__manifest__.py 0.00% <ø> (ø)
spp_oauth/models/res_config_settings.py 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Per review: env.user stays the original (possibly non-admin) user under
sudo() while env.su is True. Bypass the group check when env.su is set so
trusted server-side sudo contexts still receive the keys. The RPC attack
path is never in superuser mode, so the exposure stays closed.
@gonzalesedwin1123 gonzalesedwin1123 marked this pull request as ready for review July 2, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant